package com.example.skymallseckillproductapi.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.skymallseckillproductapi.dao.SecKillProductMapper;
import com.example.skymallseckillproductapi.service.CategoryFeignService;
import com.situ.model.Product;
import com.situ.model.ProductCategory;
import com.situ.shop.model.DTO.SecKillProductWithProductInfo;
import com.situ.shop.model.SecKillProduct;
import com.situ.shop.model.SecKillStatus;
import com.situ.shop.model.search.SecKillProductSearchBean;
import com.situ.shop.service.SecKillProductService;
import com.situ.utils.JsonResult;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;
@CacheConfig(cacheNames = "secKillProducts")
@Service
public class SecKillProductServiceImpl implements SecKillProductService {

    private SecKillProductMapper secKillProductMapper;


    private RedisTemplate<String,Object> redisTemplate;
    @Autowired
    public void setRedisTemplate(RedisTemplate<String,Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Autowired
    public void setSecKillProductMapper(SecKillProductMapper secKillProductMapper) {
        this.secKillProductMapper = secKillProductMapper;
    }

    private CategoryFeignService categoryFeignService;
    @Autowired
    public void setCategoryFeignService(CategoryFeignService categoryFeignService) {
        this.categoryFeignService = categoryFeignService;
    }


    @Override
    public SecKillProduct findById(Integer id) {
        return secKillProductMapper.selectById(id);
    }

    @Override
    public Page<SecKillProduct> findAll(Page<SecKillProduct> page, SecKillProductSearchBean searchBean) {
        return  secKillProductMapper.findAll(page,searchBean);
    }

    //根据id查该秒杀商品的具体信息
    //获取秒杀商品必须缓存,秒杀一旦开始，不允许再更改商品
    @Cacheable(key="#id")
    @Override
    public SecKillProductWithProductInfo selectByIdWithProductInfo(Integer id) {
        //缓存预热，取缓存中取到数据
        List<SecKillProductWithProductInfo> list=self().selectWithProductInfoByCondition(null);

        return list.stream().filter(item->item.getId().equals(id)).findFirst().orElse(null);

    }


    private void patch(SecKillProductWithProductInfo secKillProductWithProductInfo) {
        ResponseEntity<JsonResult<ProductCategory>> resp=this.categoryFeignService.getById(secKillProductWithProductInfo.getCategoryId());
        JsonResult<ProductCategory> jsonResult = resp.getBody();
        if (jsonResult != null) {
            secKillProductWithProductInfo.setCategory(jsonResult.getData());
        }
    }

    //查询所有秒杀商品的具体信息
    public List<SecKillProductWithProductInfo> selectAllWithProductInfo(){
        List<SecKillProductWithProductInfo> result=secKillProductMapper.selectAllWithProductInfo();

            result.forEach(this::patch);

        return result;
    }



    //根据条件查询该商品的具体信息,必须缓存预热  也就是在秒杀开始之刷新一下页面或者通过接口测试工具测试
    @Cacheable(key = "'all'")
    public List<SecKillProductWithProductInfo> selectWithProductInfoByCondition(SecKillProductSearchBean condition){


    //创建所有秒杀商品的相关信息
        List<SecKillProductWithProductInfo> result=secKillProductMapper.selectWithProductInfoByCondition(condition);
        result.forEach(this::patch);
        for(SecKillProductWithProductInfo item:result){
            //设置秒杀商品的库存
            redisTemplate.opsForValue().set("seckill-stock:"+item.getId(),item.getStock(), Duration.ofMinutes(60));
             //缓存 秒杀商品结束的标志
            redisTemplate.opsForValue().set("seckill-end:"+item.getId(),false,Duration.ofMinutes(65));
                //缓存买过的用户 这只是在初始化时创建了一个空的集合，用于存储秒杀过该商品的会员账号。
            //实际将会员添加到这个集合中的操作是在Lua脚本中完成的。
            redisTemplate.opsForSet().add("seckill-user:"+item.getId(),"");
        }
        return result;
      
    }

    /**
     * 实现秒杀核心逻辑
     * 1. 检查秒杀活动状态
     * 2. 检查库存
     * 3. 检查用户限购
     * 4. 扣减库存
     * 5. 创建订单
     */
    @Override
    public boolean processSecKill(Integer userId, Integer secKillProductId, Integer quantity) {




        // 1. 检查秒杀活动状态
        SecKillStatus status = checkSecKillStatus(secKillProductId);
        if (status != SecKillStatus.IN_PROGRESS) {
            return false; // 秒杀未开始或已结束
        }

        // 2. 检查用户是否已经购买过该秒杀商品
        if (checkUserPurchased(userId, secKillProductId)) {
            return false; // 用户已购买过
        }

        // 3. 检查库存（先从Redis中检查）
        String stockKey = "seckill:stock:" + secKillProductId;
        Integer availableStock = getAvailableStockFromRedis(stockKey);
        if (availableStock == null || availableStock < quantity) {
            // 如果Redis中没有或者库存不足，再从数据库检查
            availableStock = getAvailableStock(secKillProductId);
            if (availableStock < quantity) {
                return false; // 库存不足
            }
        }

        // 4. 预扣库存（使用Redis原子操作）
        Long decremented = redisTemplate.opsForValue().decrement(stockKey, quantity);
//将指定键 key 所存储的数值（value）减去一个给定的数量 delta，并返回执行减法操作之后的新值。
        if (decremented == null || decremented < 0) {
            // 扣减失败，恢复库存
            redisTemplate.opsForValue().increment(stockKey, quantity);
            return false;
        }

        // 5. 记录用户购买信息，防止重复购买
        String userKey = "seckill:user:" + userId + ":product:" + secKillProductId;
        redisTemplate.opsForValue().set(userKey, "1", 24, TimeUnit.HOURS);

        // 6. 发送创建订单消息到消息队列（这里简化处理，实际应该发送到MQ）
        // createOrderMessage(userId, secKillProductId, quantity);

        // 7. 异步扣减数据库真实库存（通过定时任务或消息队列实现）

        return true;
    }

    @Override
    @Cacheable(value = "secKillProductStatus", key = "#secKillProductId")
    public SecKillStatus checkSecKillStatus(Integer secKillProductId) {
        SecKillProduct product = findById(secKillProductId);
        if (product == null) {
            return SecKillStatus.ENDED; // 商品不存在，视为已结束
        }
        // 检查是否被手动下架
        if (product.getStatus() != null && product.getStatus() == 1) {
            return SecKillStatus.ENDED; // 商品已下架
        }

        LocalDateTime now = LocalDateTime.now();
        if (now.isBefore(product.getStartTime())) {
            return SecKillStatus.NOT_STARTED; // 未开始
        } else if (now.isAfter(product.getEndTime())) {
            return SecKillStatus.ENDED; // 已结束
        } else {
            // 检查库存
            Integer stock = getAvailableStock(secKillProductId);
            if (stock <= 0) {
                return SecKillStatus.SOLD_OUT; // 已售罄
            }
            return SecKillStatus.IN_PROGRESS; // 进行中
        }
    }

    @Override
    public boolean checkUserPurchased(Integer userId, Integer secKillProductId) {
        // 检查Redis中是否有用户购买记录
        String userKey = "seckill:user:" + userId + ":product:" + secKillProductId;
        Boolean hasPurchased = redisTemplate.hasKey(userKey);
        return Boolean.TRUE.equals(hasPurchased);
    }

    @Override
    @Cacheable(value = "secKillProductStock", key = "#secKillProductId")
    public Integer getAvailableStock(Integer secKillProductId) {
        // 从数据库获取实时库存
        SecKillProduct product = findById(secKillProductId);
        return product != null ? product.getStock() : 0;
    }
    //下架商品 置1
    @Override
    @CacheEvict(value = {"secKillProduct", "secKillProductPage", "secKillProductStatus", "secKillProductStock"}, allEntries = false, key = "#id")
    public boolean offShelves(Long  id) {
        SecKillProduct product= secKillProductMapper.selectById(id);
        if(product!=null){
            product.setStatus(1);
             boolean result=secKillProductMapper.updateById(product)>0;
             return result;
        }
      return false;
    }

    /**
     * 从Redis获取可用库存
     * @param stockKey 库存key
     * @return 可用库存数量
     */
    private Integer getAvailableStockFromRedis(String stockKey) {
        Object stock = redisTemplate.opsForValue().get(stockKey);
        if (stock != null) {
            try {
                return Integer.parseInt(stock.toString());
            } catch (NumberFormatException e) {
                return null;
            }
        }
        return null;
    }

    /**
     * 初始化秒杀商品库存到Redis
     * @param secKillProductId 秒杀商品ID
     */
    public void initSecKillStockInRedis(Integer secKillProductId) {
        SecKillProduct product = findById(secKillProductId);
        if (product != null) {
            String stockKey = "seckill:stock:" + secKillProductId;
            redisTemplate.opsForValue().set(stockKey, product.getStock().toString());
        }
    }

    @Override
    @CacheEvict(value = "secKillProductPage", allEntries = true)
    public boolean save(SecKillProduct seckillProduct) {
        boolean result = secKillProductMapper.insert(seckillProduct) == 1;
        // 保存成功后，初始化库存到Redis
        if (result) {
            initSecKillStockInRedis(seckillProduct.getId());
        }
        return result;
    }

    @Override
    @CacheEvict(value = "secKillProductPage", allEntries = true)
    public boolean update(SecKillProduct seckillProduct) {
        return secKillProductMapper.updateById(seckillProduct) == 1;
    }

    @Override
    @CacheEvict(value = "secKillProductPage", allEntries = true)
    public int deleteByIds(List<Integer> ids) {
        return secKillProductMapper.deleteByIds(ids);
    }

    private SecKillProductService self() {
        return (SecKillProductService) AopContext.currentProxy();
    }
}
